package ch.nostromo.tiffanys.game.chess;

import java.util.ArrayList;

import ch.nostromo.lib.util.NosTools;
import ch.nostromo.tiffanys.game.board.Board;
import ch.nostromo.tiffanys.game.board.BoardException;
import ch.nostromo.tiffanys.game.chess.pieces.Bishop;
import ch.nostromo.tiffanys.game.chess.pieces.ChessPiece;
import ch.nostromo.tiffanys.game.chess.pieces.King;
import ch.nostromo.tiffanys.game.chess.pieces.Knight;
import ch.nostromo.tiffanys.game.chess.pieces.Pawn;
import ch.nostromo.tiffanys.game.chess.pieces.Queen;
import ch.nostromo.tiffanys.game.chess.pieces.Rook;
import ch.nostromo.tiffanys.game.game.Game;
import ch.nostromo.tiffanys.game.move.MoveInput;

public class Chess {

  public static MoveInput[] getLegalMoves(Board board, int colorToMove) throws BoardException, ChessException {

    ArrayList<MoveInput> result = new ArrayList<MoveInput>();

    int ownerColor = convertColor(colorToMove);

    // Pseudo moves
    ArrayList<MoveInput> pseudoMoves = generatePseudoMoveList(board, ownerColor);

    // Filter illegal moves
    for (int i = 0; i < pseudoMoves.size(); i++) {
      Board tempBoard = null;
      try {
        tempBoard = board.clone();
      } catch (CloneNotSupportedException e) {
        throw new ChessException("Clone exception", e);
      }

      tempBoard.applyMove(pseudoMoves.get(i));

      if (!ChessPiece.isKingAttacked(tempBoard, ownerColor)) {
        result.add(pseudoMoves.get(i));
      }
    }

    return result.toArray(new MoveInput[result.size()]);

  }

  public static MoveInput[] getLegalMoves(Board board, int colorToMove, String piecePosition) throws BoardException, ChessException {

    MoveInput[] allMoves = getLegalMoves(board, colorToMove);

    ArrayList<MoveInput> result = new ArrayList<MoveInput>();

    // Filter moves
    for (int i = 0; i < allMoves.length; i++) {
      if (allMoves[i].getFrom().equalsIgnoreCase(piecePosition)) {
        result.add(allMoves[i]);
      }
    }

    return result.toArray(new MoveInput[result.size()]);

  }

  private static ArrayList<MoveInput> generatePseudoMoveList(Board board, int owner) throws BoardException {
    ArrayList<MoveInput> result = new ArrayList<MoveInput>();
    for (int i = 21; i <= 98; i++) {
      if (board.isOwnerOfField(i, owner)) {
        if (NosTools.checkMask(board.getBoardArray()[i], Board.PIECE_KNIGHT)) {
          ArrayList<MoveInput> moves = Knight.getMoveList(board, i, owner);
          result.addAll(moves);
        }
        if (NosTools.checkMask(board.getBoardArray()[i], Board.PIECE_PAWN)) {
          ArrayList<MoveInput> moves = Pawn.getMoveList(board, i, owner);
          result.addAll(moves);
        }
        if (NosTools.checkMask(board.getBoardArray()[i], Board.PIECE_KING)) {
          ArrayList<MoveInput> moves = King.getMoveList(board, i, owner);
          result.addAll(moves);
        }
        if (NosTools.checkMask(board.getBoardArray()[i], Board.PIECE_BISHOP)) {
          ArrayList<MoveInput> moves = Bishop.getMoveList(board, i, owner);
          result.addAll(moves);
        }
        if (NosTools.checkMask(board.getBoardArray()[i], Board.PIECE_QUEEN)) {
          ArrayList<MoveInput> moves = Queen.getMoveList(board, i, owner);
          result.addAll(moves);
        }
        if (NosTools.checkMask(board.getBoardArray()[i], Board.PIECE_ROOK)) {
          ArrayList<MoveInput> moves = Rook.getMoveList(board, i, owner);
          result.addAll(moves);
        }
      }
    }
    return result;

  }

  public static boolean isMate(Board board, int colorToMove) throws ChessException, BoardException {
    MoveInput[] moves = getLegalMoves(board, colorToMove);
    boolean check = isInCheck(board, colorToMove);

    return (check && moves.length == 0);
  }

  public static boolean isStaleMate(Board board, int colorToMove) throws ChessException, BoardException {

    MoveInput[] moves = getLegalMoves(board, colorToMove);
    boolean check = isInCheck(board, colorToMove);

    boolean result = (!check && moves.length == 0);
    return result;

  }

  public static boolean isMaterialRemis(@SuppressWarnings("unused") Board board) {
    return false;
  }

  public static boolean isInCheck(Board board, int colorToMove) throws BoardException {
    int ownerColor = convertColor(colorToMove);
    return ChessPiece.isKingAttacked(board, ownerColor);
  }

  private static int convertColor(int colorToMove) {
    if (colorToMove == Game.COLOR_WHITE) {
      return Board.OWNER_WHITE;
    } else {
      return Board.OWNER_BLACK;
    }
  }

}
